﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Wargame_V3_1
{
    public class ChangeType
    {
        public static dynamic ConvertObject(object value, string typeName)
        {
            Type type = GetTypeByName(typeName);
            dynamic res;
            // 如果是泛型方法或者数组，如List<T>、Dictionary<TKey, TValue>或者string[], double[], bool[]等，用反序列化转换类型
            if (type.IsGenericType || type.IsArray)
            {
                try
                {
                    res = JsonConvert.DeserializeObject(value.ToString(), type);
                    return res;
                }
                catch (Exception ex)
                {
                    Trace.TraceError($"object变量{value}转换成类型{typeName}失败：{ex.Message}");
                    return null;
                }
            }
            res = value;
            return res;
        }

        /// <summary>
        /// 将字符串数据valueString转换成由typeName（字符串）定义的类型
        /// </summary>
        /// <param name="valueString"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static dynamic ConvertString(string valueString, string typeName)
        {
            Type type = GetTypeByName(typeName);
            dynamic value;
            // 如果是泛型方法或者数组，如List<T>、Dictionary<TKey, TValue>或者string[], double[], bool[]等，用反序列化转换类型
            if (type.IsGenericType || type.IsArray)
            {
                try
                {
                    value = JsonConvert.DeserializeObject(valueString, type);
                }
                catch (Exception ex)
                {
                    Trace.TraceError($"字符串{valueString}转换成类型{typeName}失败：{ex.Message}");
                    return null;
                }
            }
            // 简单的类型，如int, string, double, bool等，直接转换
            else
            {
                try
                {
                    value = Convert.ChangeType(valueString, type);
                }
                catch (Exception ex)
                {
                    Trace.TraceError($"字符串{valueString}转换成类型{typeName}失败：{ex.Message}");
                    return null;
                }
            }
            return value;
        }

        /// <summary>
        /// 该方法根据类型名称，获取类型Type。
        /// 1. 支持string, int, double, float, bool, object等简单类型（先利用ToFullName把这些简单类型名转换成Full Name，例如System.String，如果报"没找到该类型：***"的错误，需要把Full Name的转换添加到ToFullName方法中）；
        /// 2. 支持List和Dictionary的泛型类型获取；
        /// 3. 支持本项目自定义类的类型获取，例如Operator。
        /// </summary>
        public static Type GetTypeByName(string typename)
        {
            Type t = null;
            string source = ChangeType.ToFullName(typename);
            if (source.IndexOf('<') > 0)
            {
                List<string> lv = new List<string>();
                while (Regex.IsMatch(source, @"<[^<>]+>"))
                {
                    lv.Add(Regex.Match(source, @"(?<=<)[^<>]+(?=>)").Value);
                    source = Regex.Replace(source, @"<[^<>]+>", "/" + (lv.Count - 1));
                }
                List<Type[]> args = new List<Type[]>();
                for (int i = 0; i < lv.Count; i++)
                {
                    List<Type> arg = new List<Type>();
                    string[] sp = lv[i].Split(',');
                    for (int j = 0; j < sp.Length; j++)
                    {
                        string s = sp[j].Trim();
                        if (!string.IsNullOrEmpty(s))
                        {
                            if (Regex.IsMatch(s, @"/\d+$"))
                            {
                                Match m = Regex.Match(s, @"^([^/\s]+)\s*/(\d+)$");
                                if (!m.Success)
                                {
                                    throw new Exception("");
                                }
                                Type p = GetTypeByName(m.Groups[1].Value);
                                if (p is null)
                                {
                                    throw new Exception($"没找到该类型：{m.Groups[1].Value}");
                                }
                                Type c = p.MakeGenericType(args[Convert.ToInt32(m.Groups[2].Value)]);
                                arg.Add(c);
                            }
                            else
                            {
                                Type p = GetTypeByName(s);
                                if (p is null)
                                {
                                    throw new Exception($"没找到该类型：{s}");
                                }
                                arg.Add(p);
                            }
                        }
                    }
                    args.Add(arg.ToArray());
                }
                Match f = Regex.Match(source, @"^([^/\s]+)\s*/(\d+)$");
                if (!f.Success)
                {
                    throw new Exception("");
                }
                Type fp = GetTypeByName(f.Groups[1].Value);
                Type fc = fp.MakeGenericType(args[Convert.ToInt32(f.Groups[2].Value)]);
                return fc;
            }
            else
            {
                try
                {
                    t = Type.GetType(source);
                    if (t != null)
                    {
                        return t;
                    }
                    Assembly currentAssembly = Assembly.GetExecutingAssembly();
                    Assembly[] assembly = AppDomain.CurrentDomain.GetAssemblies();
                    assembly = assembly.OrderBy(x => x != currentAssembly).ToArray();
                    foreach (Assembly ass in assembly)
                    {
                        t = ass.GetType(source);
                        if (t != null)
                        {
                            return t;
                        }
                        Type[] ts = ass.GetTypes();
                        foreach (Type st in ts)
                        {
                            if (Regex.IsMatch(st.FullName, @"\." + Regex.Escape(source) + @"(`?\d+)?$"))
                            {
                                return st;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {

                }
            }
            return t;
        }

        public static string ToFullName(string name)
        {
            string fullName = name;
            fullName = Regex.Replace(fullName, @"int", "System.Int32");
            fullName = Regex.Replace(fullName, @"string", "System.String");
            fullName = Regex.Replace(fullName, @"bool", "System.Boolean");
            fullName = Regex.Replace(fullName, @"double", "System.Double");
            fullName = Regex.Replace(fullName, @"float", "System.Single");
            fullName = Regex.Replace(fullName, @"object", "System.Object");
            return fullName;
        }
    }
}
